/**
 * @开发版权 云南赢中吉洋智能技术有限公司（YNYZ）
 * @项目名称 vfcore
 * @版本信息 v1.0
 * @开发人员 zhous
 * @开发日期 2019-09-23
 * @修订日期
 * @描述  AppConfig
 */
package com.vf.core;

import java.sql.Connection;
import java.util.LinkedList;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.cybermkd.mongo.plugin.MongoJFinalPlugin;
import com.jfinal.config.Constants;
import com.jfinal.config.Handlers;
import com.jfinal.config.Interceptors;
import com.jfinal.config.JFinalConfig;
import com.jfinal.config.Plugins;
import com.jfinal.config.Routes;
import com.jfinal.core.Controller;
import com.jfinal.ext.kit.DateKit;
import com.jfinal.ext.proxy.CglibProxyFactory;
import com.jfinal.json.MixedJsonFactory;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.dialect.MysqlDialect;
import com.jfinal.plugin.activerecord.dialect.OracleDialect;
import com.jfinal.plugin.activerecord.dialect.PostgreSqlDialect;
import com.jfinal.plugin.activerecord.dialect.SqlServerDialect;
import com.jfinal.plugin.activerecord.dialect.Sqlite3Dialect;
import com.jfinal.plugin.cron4j.Cron4jPlugin;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.plugin.ehcache.EhCachePlugin;
import com.jfinal.template.Engine;
import com.vf.core.handler.GlobalHandler;
import com.vf.core.handler.WebSocketHandler;
import com.vf.core.model.Database;
import com.vf.core.util.ReflectUtil;
import com.vf.s.common.cache.style.MapLayerCache;
import com.vf.s.common.cache.style.MapStyleCache;
import com.vf.s.common.model.biz.BizStyleLine;
import com.vf.s.common.model.biz.BizStylePoint;
import com.vf.s.common.model.biz.BizStylePolygon;
import com.vf.s.common.model.scene.BizSceneLayer;
import com.vf.s.common.plugins.shiro.ShiroPlugin;
import com.vf.s.common.plugins.shiro.ext.ShiroTag;
import com.vf.s.mvc.sync.common.task.Cron4jHttp;

public class AppConfig extends JFinalConfig {

	protected final Log log = Log.getLog(getClass());
	private static Prop p;
	public static Routes routes;

	
	@Override
	public void configConstant(Constants me) {
		log.info("-----------------configInterceptor（start）-----------------------");
		if (p == null) {
			p = PropKit.useFirstFound("app-config-pro.txt", "app-config-dev.txt");
		}
		me.setDevMode(p.getBoolean("devMode", false));
		me.setProxyFactory(new CglibProxyFactory());
		me.setJsonFactory(MixedJsonFactory.me());
		me.setInjectDependency(true);
		me.setInjectSuperClass(true);
		me.setMaxPostSize(100*1024*1024);
	}

	/**
	 * 路由拆分到 FrontRutes 与 AdminRoutes 之中配置的好处： 1：可分别配置不同的 baseViewPath 与 Interceptor
	 * 2：避免多人协同开发时，频繁修改此文件带来的版本冲突 3：避免本文件中内容过多，拆分后可读性增强 4：便于分模块管理路由
	 */
	@Override
	public void configRoute(Routes me) {
		routes = me;
		loadRoutes(p.get("app.route.file.path"), me);
	}

	/**
	 * 配置模板引擎，通常情况只需配置共享的模板函数
	 */
	@Override
	public void configEngine(Engine me) {
		me.setBaseTemplatePath(PathKit.getWebRootPath());
		me.addSharedObject("shiro", new ShiroTag());
		me.addSharedObject("JsonKit", new JsonKit());
		me.addSharedObject("dateKit", new DateKit());
		
	}

	@Override
	public void configPlugin(Plugins me) {
		loadDbConfigPlugin(me);
		me.add(new EhCachePlugin());
		ShiroPlugin shiroPlugin = new ShiroPlugin(routes);
		shiroPlugin.setLoginUrl(PropKit.get("loginUrl", ""));
		shiroPlugin.setSuccessUrl(PropKit.get("successUrl", ""));
		me.add(shiroPlugin);
		
		Cron4jPlugin alarm = new Cron4jPlugin();
		alarm.addTask("*/1 * * * *", new Cron4jHttp());
		me.add(alarm);
		
	}

	@Override
	public void configInterceptor(Interceptors me) {
		 me.addGlobalActionInterceptor(new com.vf.core.interceptor.GlobalActionInterceptor());
	}

	@Override
	public void configHandler(Handlers me) {
		me.add(new GlobalHandler());
		me.add(new WebSocketHandler("^/websocket"));
	}

	/**
	 * 加载路由配置
	 * 
	 * @param filePath
	 * @param me
	 */
	@SuppressWarnings("unchecked")
	private void loadRoutes(String filePath, Routes me) {
		
		if(StrKit.isBlank(filePath)) return;
		
		SAXReader reader;
		Document document;
		Element root;
		List<Element> elements;
		String controllerKey;
		String controllerClass;
		String viewPath;
		Controller obj = null;
		String[] arr = filePath.split(";");
		log.info("-----------------加载系统路由数量（"+arr.length+"）-----------------------");
		try {
			for (String path : arr) {
				reader = new SAXReader();
				 reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",
				 false);
				document = reader.read(AppConfig.class.getResourceAsStream("/" + path));
				if(document==null) return;
				root = document.getRootElement();
				elements = root.elements();
				for (Element element : elements) {
					controllerKey = element.elementText("controllerKey");
					controllerClass = element.elementText("controllerClass");
					viewPath = element.elementText("viewPath");
					if (!StrKit.isBlank(controllerKey) && !StrKit.isBlank(controllerClass)) {
						obj = ReflectUtil.on(controllerClass).create().get();
						if (!StrKit.isBlank(viewPath)) {
							me.add(controllerKey, obj.getClass(), viewPath);
						} else {
							me.add(controllerKey, obj.getClass());
						}
					}
				}
			}
		} catch (DocumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 加载数据库配置信息
	 * 
	 * @param me
	 */
	private void loadDbConfigPlugin(Plugins me) {

		log.info("-----------------加载系统管理数据源（start）-----------------------");
		List<Database> list = parseXmlToList(p.get("app.db.file.path"));
		DruidPlugin druidPlugin;
		ActiveRecordPlugin arp;
		for (Database bean : list) {
			if(StrKit.equals("MongoDB", bean.getType())) {
				MongoJFinalPlugin jFinalPlugin = new MongoJFinalPlugin();
				jFinalPlugin.add(bean.getUrl(),bean.getPort());
				jFinalPlugin.setDatabase(bean.getName());
				me.add(jFinalPlugin);
			}else {
				druidPlugin = new DruidPlugin(bean.getUrl(), bean.getUser(), bean.getPassword());
				if (!"sqlite".equalsIgnoreCase(bean.getType())) druidPlugin.set(bean.getInitialSize(), bean.getMinIdle(), bean.getMaxActive());
				arp = new ActiveRecordPlugin(bean.getName(), druidPlugin);
				arp.setShowSql(bean.isShowSql());
				arp.setTransactionLevel(Connection.TRANSACTION_READ_COMMITTED);
				arp.getEngine().setToClassPathSourceFactory();
				if (!StrKit.isBlank(bean.getSqlTemplate())) {
					arp.addSqlTemplate(bean.getSqlTemplate());
				}

				if (bean.getMappingClassList() != null && bean.getMappingClassList().size() > 0) {
					for (String mappingClass : bean.getMappingClassList()) {
						ReflectUtil.on(mappingClass).call("mapping", arp);
					}
				}

				if ("oracle".equalsIgnoreCase(bean.getType())) {
					druidPlugin.setDriverClass(bean.getDriverClass());
					arp.setDialect(new OracleDialect());
					
				} else if ("mysql".equalsIgnoreCase(bean.getType())) {
					arp.setDialect(new MysqlDialect());
				} else if ("sqlserver".equalsIgnoreCase(bean.getType())) {
					arp.setDialect(new SqlServerDialect());
				}
				else if ("sqlite".equalsIgnoreCase(bean.getType())) {
					druidPlugin.setDriverClass(bean.getDriverClass());
					arp.setDialect(new Sqlite3Dialect());
				}
				else if ("postgresql".equalsIgnoreCase(bean.getType())) {
					druidPlugin.setDriverClass(bean.getDriverClass());
					arp.setDialect(new PostgreSqlDialect());
				}
				// arp.setContainerFactory(new CaseInsensitiveContainerFactory(true));//false
				// 是大写, true是小写, 不写是区分大小写
				me.add(druidPlugin);
				me.add(arp);
			}
		}
		log.info("-----------------加载系统管理数据源（end）-size(" + list.size() + ")----------------------");
	}
	
	@SuppressWarnings("unchecked")
	public static List<Database> parseXmlToList(String filePath) {
		List<Database> lists = new LinkedList<Database>();
		try {
			SAXReader reader = new SAXReader();
			reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
			Document document = reader.read(AppConfig.class.getResourceAsStream("/" + filePath));
			
			Element root = document.getRootElement();
			List<Element> elements = root.elements();

			List<Element> mappingClass;
			Database bean;
			for (Element element : elements) {
				bean = new Database();
				bean.setName(element.elementText("name"));
				bean.setType(element.elementText("type"));
				bean.setUser(element.elementText("user"));
				bean.setPassword(element.elementText("password"));
				bean.setUrl(element.elementText("url"));

				if(element.element("mappingClass").elements()!=null) {
					mappingClass = element.element("mappingClass").elements();
					if (mappingClass != null && mappingClass.size() > 0) {
						List<String> eleList = new LinkedList<String>();
						for (Element ele : mappingClass) {
							eleList.add(ele.getText());
						}
						bean.setMappingClassList(eleList);
					}
				}

				if(!StrKit.isBlank(element.elementText("port"))) {
					bean.setPort(Integer.parseInt(element.elementText("port")));
				}
				if(!StrKit.isBlank(element.elementText("initialSize"))) {
					bean.setInitialSize(Integer.parseInt(element.elementText("initialSize")));
				}
				if(!StrKit.isBlank(element.elementText("minIdle"))) {
					bean.setMinIdle(Integer.parseInt(element.elementText("minIdle")));
				}
				if(!StrKit.isBlank(element.elementText("maxActive"))) {
					bean.setMaxActive(Integer.parseInt(element.elementText("maxActive")));
				}
				if(!StrKit.isBlank(element.elementText("showSql"))) {
					bean.setShowSql(Boolean.parseBoolean(element.elementText("showSql")));
				}
				if(!StrKit.isBlank(element.elementText("driverClass"))) {
					bean.setDriverClass(element.elementText("driverClass"));
				}
				lists.add(bean);
			}
		} catch (DocumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return lists;
	}
	

	@Override
	public void afterJFinalStart() {
		List<BizStylePoint> bizStylePoints=BizStylePoint.dao.find("SELECT * FROM "+BizStylePoint.TABLE_NAME);
		for(BizStylePoint obj:bizStylePoints) {
			MapStyleCache.put(obj.getId(), obj);
		}
		List<BizStylePolygon> bizStylePolygons=BizStylePolygon.dao.find("SELECT * FROM "+BizStylePolygon.TABLE_NAME);
		for(BizStylePolygon obj:bizStylePolygons) {
			MapStyleCache.put(obj.getId(), obj);
		}
		List<BizStyleLine> bizStyleLines=BizStyleLine.dao.find("SELECT * FROM "+BizStyleLine.TABLE_NAME);
		for(BizStyleLine obj:bizStyleLines) {
			MapStyleCache.put(obj.getId(), obj);
		}
		
		List<BizSceneLayer> bizSceneLayers=BizSceneLayer.dao.find("SELECT * FROM "+BizSceneLayer.TABLE_NAME);
		for(BizSceneLayer obj:bizSceneLayers) {
			MapLayerCache.put(obj.getId(), obj);
		}
	}
}
